package com.keffect.effects;

import java.util.Timer;
import java.util.TimerTask;

import com.keffect.KEffect;
import com.keffectpanel.KEffectPanel;

/**
 * This class implements an effect that has an animation. When the
 * {@link #start()} operation is invoked, the animation will start, and then
 * stop after fulfilled the duration time that has been set.
 * 
 * In every unit of time a frame will be painted on the panel object of the
 * class {@link KEffectPanel}, so that the animation will be simulated.
 * 
 * @author Matias Varela
 *         <p>
 *         Student of Licenciatura en Ciencias de la Computacion, at the
 *         Universidad Nacional del Sur (Argentina).
 *         <p>
 *         project site: http://code.google.com/p/keffect-project/
 * 
 * 
 */
public abstract class AnimatedEffect implements KEffect, Animated {

	protected long duration;
	protected Timer timer;
	protected TimerTask timer_task;
	protected KEffectPanel panel;
	protected boolean isRunning;

	/* the amount of frames that correspond with the effect. */
	protected long frames;


	/**
	 * Constructs an animated effect.
	 * 
	 * @param duration
	 *            the duration time (in milliseconds) of the graphic effect.
	 */
	public AnimatedEffect(long duration) {
		this.duration = duration;
		this.frames=1;
	}


	/* <<< QUERIES >>> */

	@Override
	public long getFrames() {
		return this.frames;
	}


	@Override
	public boolean isActive() {
		return (this.panel != null) && isRunning && this.isRunning();
	}


	/**
	 * Returns the condition that must satisfy the animated effect while it is
	 * running.
	 * 
	 * @see #isActive()
	 * @return <code>true</code> if the animated effect is running;
	 *         <code>false</code> otherwise.
	 */
	public abstract boolean isRunning();


	@Override
	public KEffectPanel getEffectPanel() {
		return panel;
	}


	/* <<< COMMANDS >>> */
	@Override
	public void setFrames(long frames) {
		this.frames = frames;
	}


	@Override
	public void setEffectPanel(KEffectPanel panel) {
		this.panel = panel;
	}


	@Override
	public void setDuration(long time) {
		this.duration = time;
	}


	@Override
	public void start() {
		if (panel == null) throw new NullPointerException("No KEffectPanel defined for this effect.");
		else {
			// if there is a previous effect running, then it must stop.
			stop();
			this.initEffectProperties();

			// create a new action effect.
			timer = new Timer();
			timer_task = new TimerTask() {

				@Override
				public void run() {
					if (AnimatedEffect.this.isRunning()) {
						AnimatedEffect.this.run();
						if (AnimatedEffect.this.panel.getParent() != null) AnimatedEffect.this.panel.getParent().repaint();

					} else AnimatedEffect.this.stop();
				}
			};

			try {
				// get the period time between each frame.
				long d = duration / frames;
				d = d > 0 ? d : 1;  // d > 0
				isRunning = true;

				// start running the graphic effect logic.
				timer.scheduleAtFixedRate(timer_task, 0, d);
				
			} catch (IllegalStateException e) {
			}
		}
	}


	@Override
	public void stop() {
		if (timer_task != null) {
			timer_task.cancel();
			timer_task = null;
		}
		if (timer != null) {
			timer.cancel();
			timer.purge();
			timer = null;
		}
		isRunning = false;

	}

}
